package gee

import (
	"fmt"
	"log"
	"net/http"
	"runtime"
	"strings"
)

func trace(message string) string {
	// 声明一个长度为32的uintptr数组用于存储调用栈信息
	var pcs [32]uintptr

	// 调用runtime.Callers方法获取调用栈信息（跳过前3个caller），并返回调用栈中的函数调用信息的数量
	n := runtime.Callers(3, pcs[:])

	// 创建一个strings.Builder类型的变量用于构建字符串
	var str strings.Builder
	// 将传入的message和"Traceback:"字符串写入到字符串构建器中
	str.WriteString(message + "\nTraceback:")

	// 遍历调用栈信息中的每个函数调用信息
	for _, pc := range pcs[:n] {
		// 获取与指定程序计数器（pc）相关联的函数
		fn := runtime.FuncForPC(pc)
		// 获取函数所在的文件和行号信息
		file, line := fn.FileLine(pc)
		// 将文件路径和行号信息格式化后写入到字符串构建器中
		str.WriteString(fmt.Sprintf("\n\t%s:%d", file, line))
	}

	// 返回构建的完整字符串
	return str.String()
}

func Recovery() HandlerFunc {
	return func(c *Context) {
		defer func() {
			if err := recover(); err != nil {
				message := fmt.Sprintf("%s", err)
				log.Printf("%s\n\n", trace(message)) //trace 将 message 中的消息进行追踪，打印
				c.Fail(http.StatusInternalServerError, "Internal Server Error")
			}
		}()

		c.Next()
	}
}
